package ca.uvic.group2.testHarness;

import java.io.*;
import java.util.*;
import java.net.*;
import org.apache.log4j.*;

public class TestManager {

    static private int count = 0;
    static public synchronized int getCount() {
	return ++count;
    }


    private static void usage() {
        System.err.println("Usage: TestManager workload-file [timelimit] [usersPerFile] [maxUsers] [maxTransactionsPerFile]");
        System.exit(1);
    }

    public static void main(String[] args) {
        if (args.length < 1) {
            usage();
        }

        String filename = args[0];
        int timelimit = 0;
        int usersPerFile = 50;
        int maxUsers = 0;
        int maxCommands = 0;

        if (args.length > 1) {
            int tmp = Integer.parseInt(args[1]);
            if (tmp > 0) {
                timelimit = tmp;
            }
        }

        if (args.length > 2) {
            int tmp = Integer.parseInt(args[2]);
            if (tmp > 0) {
                usersPerFile = tmp;
            }
        }

        if (args.length > 3) {
            int tmp = Integer.parseInt(args[3]);
            if (tmp > 0) {
                maxUsers = tmp;
            }
        }

        if (args.length > 4) {
            int tmp = Integer.parseInt(args[4]);
            if (tmp > 0) {
                maxCommands = tmp;
            }
        }

        System.out.println("Work File Name: " + filename);
        System.out.println("Timelimit: " + String.valueOf(timelimit) + " sec");
        System.out.println("Users per file: " + String.valueOf(usersPerFile));
        System.out.println("Max Users: " + String.valueOf(maxUsers));
        System.out.println("Max Commands: " + String.valueOf(maxCommands));

        TestManager man = new TestManager(filename, timelimit, usersPerFile, maxUsers, maxCommands);
        man.run();
    }

    private HashMap userMap = new HashMap();
    private String[] filenames;
    private String filename;
    private int timelimit;
    private float totalTps = 0.0f;
    private float numTps = 0.0f;
    private float totalTimeToComplete = 0.0f;
    private float numTimeToComplete = 0.0f;
    private int numTransactions = 0;

    public TestManager(String filename, int timelimit, int usersPerFile, int maxUsers, int maxCommands) {
        this.filename = filename;
        this.timelimit = timelimit;
        this.filenames = DistributeTest.initBreakUp(filename, userMap, usersPerFile, maxUsers, maxCommands, false);
    }

    private static final String[] HOSTS = {
//         "c150",
//         "c151",
//         "c152",
//         "c153",
//         "c154",
//         "c155",
//         "c156",
//         "c157",
//         "c158",
//         "c159",
//         "c160",
//         "c161",
         "c162",
         "c163",
	 "c164",
         "c165",
         "c166",
         "c167",
	 "c168",
	 "c169",
	 "c170",
	 "c171",
	 "c172",
	 "c173",
	 "c174",
	 "c175",
	 "c176",
	 "c177",
	 "c178",
	 "c179",
	 "c180",
	 "c181",
	 "c182",
	 "c183",
	 "c184",
	 "c185",
	 "c186",
	 "c187",
	 "c188",
	 //         "c189",
	 "c190"
    };


    public void run() {
        System.out.println("TestManager: Performing init.");
        new WSConnectionManager().commandInit();
        System.out.println("TestManager: Init Complete.");

        int numFiles = filenames.length;
        if (numFiles > HOSTS.length) {
            System.out.println("Given " + numFiles + " workload files, but there are only " + HOSTS.length);
            numFiles = HOSTS.length;
        }

        System.out.println("Starting " + String.valueOf(numFiles) + " clients, from " + HOSTS[0] + " to " + HOSTS[numFiles-1]);

        ClientRunner[] clients = new ClientRunner[numFiles];

        for (int i = 0; i < numFiles; ++i) {
            clients[i] = new ClientRunner(HOSTS[i], filenames[i], timelimit);
            clients[i].start();

	    try {
		Thread.sleep(2000);
	    } catch (InterruptedException ignored) {
	    }
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException ignored) {
        }

        for (int i = 0; i < numFiles; ++i) {
            try {
                clients[i].join();
            } catch (InterruptedException ignored) {
            }
            System.out.println("Client " + clients[i].getHostName() + ":" + clients[i].getFileName());
            System.out.println(clients[i].getOutput());

            float tps = clients[i].getTps();
            if (tps <= 0.0) {
                System.out.println("Could not get TPS");
            } else {
                totalTps += tps;
                numTps++;
            }

            int tmp = clients[i].getNumTransactions();
            if (tmp <= 0) {
                System.out.println("Could not get numTransacitons");
            } else {
                numTransactions += tmp;
            }

            tps = clients[i].getTimeToComplete();
            if (tps <= 0.0) {
                System.out.println("Could not get TimeToComplete");
            } else {
                totalTimeToComplete += tps;
                numTimeToComplete++;
            }


            System.out.println("");
        }

        System.out.println("Avg TPS: " + totalTps + ", Machine Count: " + numTps);
        System.out.println("Num Transactions: " + numTransactions);
        System.out.println("Avg Time to Complete: " + (totalTimeToComplete / numTimeToComplete));

        // Get Dumplog
        System.out.println("Getting Dumplog...");
        new WSConnectionManager().commandStopStats();
        new WSConnectionManager().commandDumplog();

    }

    private static class ClientRunner extends Thread {
        private StringBuffer output = new StringBuffer();
        private String hostname;
        private String filename;
        private int timelimit;
        private float tps = 0;
        private float timeToComplete = 0;
        private int numTransactions = 0;

        public ClientRunner(String hostname, String filename, int timelimit) {
            this.hostname = hostname;
            this.filename = filename;
            this.timelimit = timelimit;
        }

        public void run() {
            String remoteCommand = ". ~/.bash_profile;cd $ROOT462;./runlocaltest.sh " + filename + " " + timelimit;
            String command = "ssh " + hostname + " \"" + remoteCommand + "\"";
            System.out.println("Running command: " + command);
            ProcessBuilder pb = new ProcessBuilder("ssh", hostname, remoteCommand);
            pb.redirectErrorStream(true);

            try {
                Process child = pb.start();
                BufferedReader input = new BufferedReader(new InputStreamReader(child.getInputStream()));
                String line;

                while ((line = input.readLine()) != null) {
		    if (line.startsWith("SESSIONID")) {
			int count = TestManager.getCount();
			System.out.println("Session " + count + ":" + hostname + ": " + line);
		    } else {
			System.out.println(hostname + ": " + line);
		    }
                    if (line.startsWith("Transaction per Second")) {
                        try {
                            this.tps = Float.parseFloat(line.substring("Transaction per Second: ".length()));
                        } catch (Exception err) {
                            this.tps = -1;
                        }
                    } else if (line.startsWith("Number of transactions: ")) {
                        try {
                            this.numTransactions = Integer.parseInt(line.substring("Number of transactions: ".length()));
                        } catch (Exception err) {
                            this.numTransactions = -1;
                        }
                    } else if (line.startsWith("Time to Complete: ")) {
                        try {
                            this.timeToComplete = Float.parseFloat(line.substring("Time to Complete: ".length()));
                        } catch (Exception err) {
                            this.timeToComplete = -1;
                        }
                    }
                    output.append(line + "\n");
                }
            } catch (IOException err) {
                err.printStackTrace();
            }
        }

        public String getOutput() {
            return output.toString();
        }

        public String getHostName() {
            return hostname;
        }

        public String getFileName() {
            return filename;
        }

        public float getTps() {
            return tps;
        }

        public float getTimeToComplete() {
            return timeToComplete;
        }

        public int getNumTransactions() {
            return numTransactions;
        }
    }
}
